import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:freedom/util/customer_dialog.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

/// 规范一下函数入参

typedef ConSuccess = void Function(WebSocketSink webSocket);
typedef OnMessage = void Function(dynamic content);

class SocketServer {
  static SocketServer? _instance; // 静态变量

// 心跳时间
  static int heartTime = 5;

  static String closeMessage = "===xBL6LzLD^eQnKLwtkKgCM9^wbTKmYR2C===";

  final StreamController<String> _streamController =
      StreamController.broadcast();

  StreamSink<String> get messageSink => SocketServer()._streamController.sink;

  Stream<String> get messageSteam => SocketServer()._streamController.stream;

  factory SocketServer() {
    _instance ??= SocketServer._();
    return _instance!;
  }

  SocketServer._();
  // 长连接对象
  WebSocketSink? _webSocket;

  // 定时心跳任务,保证存活  5秒一次  发送消息
  Timer? _heartTimer;

  /// 值得注意的是启动心跳如果报错了
  /// 你是不能直接将Timer停止的

  void _startHeart(String url, String token,
      {ConSuccess? conSuccess,
      Function? conError,
      OnMessage? onMessage,
      Function? onHeart}) {
    _heartTimer?.cancel();
    _heartTimer = null;
    if (_heartTimer != null) {
      return;
    }
    _heartTimer =
        Timer.periodic(Duration(seconds: heartTime), (Timer timer) async {
      try {
        if (_webSocket == null) {
          connect(url, token,
              conError: conError,
              conSuccess: conSuccess,
              onMessage: onMessage,
              onHeart: onHeart);
        }
      } catch (e) {
        connect(url, token,
            conError: conError, conSuccess: conSuccess, onHeart: onHeart);
      }
    });
  }

  // 监听事件
  void onData(dynamic content, OnMessage? onMessage) {
    if (content == null) {
      return;
    }
    if (onMessage != null) {
      messageSink.add(content);
      onMessage(content);
    }
  }

  Future<void> waitThrow(String message) async {
    throw Exception(message);
  }

  void doSuccess(ConSuccess? conSuccess) {
    if (conSuccess == null) {
      return;
    }
    try {
      conSuccess(_webSocket!);
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

  void doFun(Function? fun) {
    if (fun == null) {
      return;
    }
    try {
      fun();
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

  void connect(String url, String token,
      {ConSuccess? conSuccess,
      Function? conError,
      OnMessage? onMessage,
      Function? onHeart,
      Function? serverClose}) async {
    _startHeart(url, token,
        conError: conError,
        conSuccess: conSuccess,
        onMessage: onMessage,
        onHeart: onHeart);
    if (_webSocket != null) {
      doSuccess(conSuccess);
      return;
    }
    CustomerDialog.loading("连接中...");
    void callback(Stream stream, WebSocketSink webSink) {
      _webSocket = webSink;
      CustomerDialog.closeLoading();
      stream.listen((content) {
        if (content == closeMessage) {
          doFun(serverClose);
          closeSocket();
          return;
        }
        onData(content, onMessage);
      }, onError: (a) {
        _webSocket?.close();
        _webSocket = null;
        doFun(conError);
      }, onDone: () {
        _webSocket?.close();
        _webSocket = null;
        doFun(conError);
      });
      doSuccess(conSuccess);
    }

    if (kIsWeb) {
      WebSocketChannel socketChannel = WebSocketChannel.connect(
        Uri.parse(url),
        protocols: [token],
      );
      await socketChannel.ready.then((result) {
        callback(
          socketChannel.stream,
          socketChannel.sink,
        );
      }).timeout(const Duration(seconds: 3), onTimeout: () {
        socketChannel.sink.close();
      });
    } else {
      IOWebSocketChannel socketChannel = IOWebSocketChannel.connect(url,
          pingInterval: const Duration(seconds: 5), protocols: [token]);
      await socketChannel.ready.then((result) {
        callback(
          socketChannel.stream,
          socketChannel.sink,
        );
      }).timeout(const Duration(seconds: 3), onTimeout: () {
        socketChannel.sink.close();
      });
    }
  }

  void closeSocket() {
    _heartTimer?.cancel();
    _webSocket?.close();
    _webSocket = null;
  }

  // 向服务器发送消息
  void sendMessage(dynamic message) {
    Future(() {
      _webSocket?.add(message);
    });
  }
}
